iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
DevOps

那些文件沒告訴你的 AWS EKS系列 第 24

[24] 為什麼 EKS worker node IP address 容易佔用 IP 或是 subnets IP 地址不夠(二)

  • 分享至 

  • xImage
  •  

接續昨日的環境,透過 CloudTrail API 紀錄查看是哪時候以及是誰協助關聯 secondary IP 地址給 node 上。以下為部分 AssignPrivateIpAddresses API 紀錄:

{
    "eventVersion": "1.08",
    "userIdentity": {
        ...
        ...
        ...
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROAYFMQSNSE4F5IBB2AB",
                "arn": "arn:aws:iam::111111111111:role/eksctl-ironman-2022-addon-iamserviceaccount-kube-Role1-EMRZZYBVKCRL",
                "accountId": "111111111111",
                "userName": "eksctl-ironman-2022-addon-iamserviceaccount-kube-Role1-EMRZZYBVKCRL"
            },
            "webIdFederationData": {
                "federatedProvider": "arn:aws:iam::111111111111:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
                "attributes": {}
            },
            "attributes": {
                "creationDate": "2022-10-05T13:15:45Z",
                "mfaAuthenticated": "false"
            }
        }
    },
    "eventTime": "2022-10-05T13:16:06Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "AssignPrivateIpAddresses",
    "awsRegion": "eu-west-1",
    "sourceIPAddress": "52.210.231.138",
    "userAgent": "amazon-vpc-cni-k8s/version/ aws-sdk-go/1.40.6 (go1.16.10; linux; amd64)",
    "requestParameters": {
        "networkInterfaceId": "eni-0bbea279695112970",
        "privateIpAddressesSet": {},
        "secondaryPrivateIpAddressCount": 9,
        "ipv4Prefixes": {}
    },
    "responseElements": {
        "requestId": "c03ec3be-6a39-4138-9dd9-7d1ed04d7971",
        "networkInterfaceId": "eni-0bbea279695112970",
        "assignedPrivateIpAddressesSet": {
            "assignedPrivateIpAddressSetType": [
                {
                    "privateIpAddress": "192.168.53.76"
                },
                {
                    "privateIpAddress": "192.168.41.30"
                },
                {
                    "privateIpAddress": "192.168.47.240"
                },
                {
                    "privateIpAddress": "192.168.47.144"
                },
                {
                    "privateIpAddress": "192.168.61.98"
                },
                {
                    "privateIpAddress": "192.168.35.36"
                },
                {
                    "privateIpAddress": "192.168.61.68"
                },
                {
                    "privateIpAddress": "192.168.51.85"
                },
                {
                    "privateIpAddress": "192.168.52.54"
                }
            ]
        },
        "assignedIpv4PrefixSet": {},
        "_return": true
    },
    ...
    ...

關注到 userAgent 來源為 amazon-vpc-cni-k8s 並關聯了 9 個 private IP 至 eni-0bbea279695112970 也就是 EKS worker node i-03846c730abe852f4 上關聯第二張 Elastic network interfaces(ENI) [1]。

為什麼 VPC CNI plugin 會關聯數個 IP 地址

在 VPC 環境中,如果需要建立新的 ENI 資源則需要指定 subnet id,然而 EC2 基於不同的 instance type 也有對應每張 ENI 網卡可以關聯 IP 地址的上限限制。在不同的 EC2 instance type 下,可以關聯 ENI 數量、private IP 地址總數也不進相同。

以 instance type m5.large 為例:最多可以關聯 3 張 ENI,每張 ENI 可最高關聯 10 個 private IP 地址,因此每個 instance type m5.large EC2 最多可以使用 30 個 private IP。

VPC CNI plugin 中 ipamd(IP Address Management (IPAM) daemon )元件主要就是負責管理整合一個 IP 地址 warm-pool 並指派 IP 需要使用的 Pod ,倘若若對於 EKS 如何知道使用 VPC CNI plugin 則可以參考 Day5 [2] 說明。

預設 VPC CNI plugin 行為

在此討論的是 node 加入 cluster 後 aws-node Pod 成功執行後的行為。預設額外關聯一張 ENI,並且關聯最多可以關聯的 private IP 地址的上限 [3]。

如同 i-03846c730abe852f4 instance type m5.large 可以觀察到每一張 ENI 都關聯了 10 個 private IP 地址,可藉由 aws ec2 describe-instances 命令查看:

$ aws ec2 describe-instances --instance-ids i-03846c730abe852f4 --query "Reservations[*].Instances[*].NetworkInterfaces[]"

同時,我們也可以觀察到 aws-node 預設設定了環境變數 WARM_ENI_TARGET 為 1。

$ kubectl -n kube-system get ds aws-node -o yaml | grep -A1 "name: WARM"
        - name: WARM_ENI_TARGET
          value: "1"
        - name: WARM_PREFIX_TARGET
          value: "1"
  • WARM_ENI_TARGET 代表 ipamd 保留多少可用的 ENI 數量。以預設設定為例,除了原先 ENI 之外,額外關聯一張 ENI 並關聯相應 private IP 地址以確保未來 Pod IP 地址可以使用。倘若 IP 數量太少(或太多)時,則會呼叫 EC2 API attach(或 detach) ENI 及 private IP。

WARM_ENI_TARGET、WARM_IP_TARGET 及 MINIMUM_IP_TARGET 環境變數

除了上述 WARM_ENI_TARGET 環境變數之外,VPC CNI plugin 提供了兩個 WARM_IP_TARGETMINIMUM_IP_TARGET 環境變數[4] 可以讓使用者調整 Node 上 IP 數量。

  • WARM_IP_TARGETipamd 保留多少可用的 IP 地址數量。
  • MINIMUM_IP_TARGETipamd 在 node 上指派 IP 地址的總數「下限」。

因此我們可以藉由設定 MINIMUM_IP_TARGET 環境變數來調整預設 VPC CNI plugin 以避免 subnet IP 地址耗盡問題。

$ kubectl set env daemonset -n kube-system aws-node MINIMUM_IP_TARGET=5
daemonset.apps/aws-node env updated

設定環境變數會使 aws-node 重啟,待幾分鐘後,再次使用 describe-instances 檢視 IP 地址數量,確認 IP 地址數量僅剩 5 個。

$ $ aws ec2 describe-instances --instance-ids i-03846c730abe852f4 --query Reservations[*].Instances[*].NetworkInterfaces[*].PrivateIpAddresses[*].PrivateIpAddress
[
    [
        [
            [
                "192.168.55.245",
                "192.168.49.56",
                "192.168.41.36",
                "192.168.49.142",
                "192.168.45.23",
                "192.168.62.119"
            ]
        ]
    ]
]

在小型或是 Pod 穩定的 cluster 可以設定 WARM_IP_TARGET 作為保留 Pod IP 地址數量,同時也可以設定 MINIMUM_IP_TARGET 略高於計劃在每個 node 上執行的 pod 的預期數量。

避免將 WARM_IP_TARGET 數值設定太低,這可能會導致呼叫過多次數 EC2 API 導致 API throttling。 對於大型集群,則可以搭配 MINIMUM_IP_TARGET 一起使用以避免 API throttling。

監控

根據 VPC CNI plugin YAML manifest [5],也提供 61678 port metrics 可讓使用者監控當前 node 上的 IP 地址。

...
      containers:
        - name: aws-node
          image: "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.11.4"
          ports:
            - containerPort: 61678
              name: metrics
..

以下為登入其中一台 EKS worker node 進行測試:

[ec2-user@ip-192-168-18-190 ~]$ sudo netstat -ntupl | grep "61678"
tcp6       0      0 :::61678                :::*                    LISTEN      11283/./aws-k8s-age

[ec2-user@ip-192-168-18-190 ~]$ ps auxf | grep -B2 "11283"
...
...
root     11213  0.0  0.1 712204  9892 ?        Sl   15:32   0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 13b9c3b2469aaa79ef46b1f67bc91a8e9ce2e18d0a9330935fc44fb8f9040ec4 -address /run/containerd/containerd.sock
root     11232  0.0  0.0  11556  2604 ?        Ss   15:32   0:00  \_ bash /app/entrypoint.sh
root     11283  0.0  0.7 760228 57028 ?        Sl   15:32   0:00      \_ ./aws-k8s-agen
[ec2-user@ip-192-168-18-190 ~]$ curl -s localhost:61678/metrics | grep "ip_addresses"
# HELP awscni_assigned_ip_addresses The number of IP addresses assigned to pods
# TYPE awscni_assigned_ip_addresses gauge
awscni_assigned_ip_addresses 2
# HELP awscni_total_ip_addresses The total number of IP addresses
# TYPE awscni_total_ip_addresses gauge
awscni_total_ip_addresses 12

上述輸出為 aws-k8s-agentprocess 使用 61678 port,此正是 aws-node Pod 的 ipamd,並於 node 上提供 Prometheus [6] 格式指標。

總結

VPC CNI plugin 提供了三個不同 WARM_ENI_TARGETWARM_IP_TARGETMINIMUM_IP_TARGET 環境變數讓使用者可以更好的調整 ipamd 調整每個 node 上 warm pool 方式。

倘若需要進行監控每個 node 上 IP 數量最佳化,則可以透過 Prometheus 來收集 61678 port metrics。

參考文件

  1. Elastic network interfaces - https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html
  2. [05] 為什麼 EKS cluster 知道預設 CNI Plugin 為 Amazon VPC CNI plugin - https://ithelp.ithome.com.tw/articles/10294832
  3. https://github.com/aws/amazon-vpc-cni-k8s#eni-allocation
  4. WARM_ENI_TARGET, WARM_IP_TARGET and MINIMUM_IP_TARGET - https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/eni-and-ip-target.md
  5. https://github.com/aws/amazon-vpc-cni-k8s/blob/master/config/master/aws-k8s-cni.yaml#L144-L149
  6. Prometheus - https://prometheus.io/

上一篇
[23] 為什麼 EKS worker node IP address 容易佔用 IP 或是 subnets IP 地址不夠(一)
下一篇
[25] 為什麼 EKS add-on 可以管理 Kubernetes plugin
系列文
那些文件沒告訴你的 AWS EKS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言